from typing import List, Union

from emi.util import BarBox
from pyecharts import charts
import pyecharts.options as opts
from pyecharts.commons.utils import JsCode

from emiui.chart import KChart

class MACD(KChart):

    def __init__(self, fast_period: int = 12,slow_period: int = 26,signal_period: int = 9):
        self.fast_period = fast_period
        self.slow_period = slow_period
        self.signal_period = signal_period

    def make_chart(self, k_model, is_line: bool, title:str, x_list: List[str],**param):
        bar_box = BarBox(full_size=35)
        diff_list = []
        dea_list = []
        bar_list = []
        for k_item  in k_model.k_items:
            bar_box.add(k_item.bar)
            dif, dea, bar = bar_box.macd(fast_period=self.fast_period,slow_period=self.slow_period,signal_period = self.signal_period,array=False)
            diff_list.append(dif)
            dea_list.append(dea)
            bar_list.append(bar)

        chart_line = charts.Line()
        chart_line.add_xaxis(xaxis_data=x_list)
        chart_line.add_yaxis(
                series_name=f"diff",
                y_axis=diff_list,
                is_smooth=True,
                is_hover_animation=False,
                linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
                label_opts=opts.LabelOpts(is_show=False),
                # tooltip_opts=opts.TooltipOpts(is_show=False)
            )
        chart_line.add_yaxis(
            series_name=f"dea",
            y_axis=dea_list,
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
            label_opts=opts.LabelOpts(is_show=False),
            # tooltip_opts=opts.TooltipOpts(is_show=False)
        )
        chart_line.add_yaxis(
            series_name=f"bar",
            y_axis=bar_list,
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
            label_opts=opts.LabelOpts(is_show=False),
            # tooltip_opts=opts.TooltipOpts(is_show=False)
        )
        chart_line.set_global_opts(xaxis_opts=opts.AxisOpts(type_="category"))

        return chart_line

class KDJ(KChart):

    def __init__(self,fast_period = 9,slow_period = 3):
        self.fast_period = fast_period
        self.slow_period = slow_period

    def make_chart(self, k_model, is_line: bool, title:str, x_list: List[str],**param):
        bar_box = BarBox(full_size=30)
        k_list = []
        d_list = []
        j_list = []
        for k_item  in k_model.k_items:
            bar_box.add(k_item.bar)
            k,d,j = bar_box.kdj(fast_period=self.fast_period,slow_period=self.slow_period,array=False)
            k_list.append(k)
            d_list.append(d)
            j_list.append(j)

        chart_line = charts.Line()
        chart_line.add_xaxis(xaxis_data=x_list)
        chart_line.add_yaxis(
                series_name=f"K",
                y_axis=k_list,
                is_smooth=True,
                is_hover_animation=False,
                linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
                label_opts=opts.LabelOpts(is_show=False),
                # tooltip_opts=opts.TooltipOpts(is_show=False)
            )
        chart_line.add_yaxis(
            series_name=f"D",
            y_axis=d_list,
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
            label_opts=opts.LabelOpts(is_show=False),
            # tooltip_opts=opts.TooltipOpts(is_show=False)
        )
        chart_line.add_yaxis(
            series_name=f"J",
            y_axis=j_list,
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
            label_opts=opts.LabelOpts(is_show=False),
            # tooltip_opts=opts.TooltipOpts(is_show=False)
        )
        chart_line.set_global_opts(xaxis_opts=opts.AxisOpts(type_="category"))

        return chart_line



class KChart_Vol(KChart):
    """
    成交量图
    """
    def make_chart(self, k_model, is_line: bool, title:str, x_list: List[str],**param):
        volume_list = [int(k_item.vol) for k_item in k_model.k_items]
        bar_1 = (
            charts.Bar()
                .add_xaxis(xaxis_data=x_list)
                .add_yaxis(
                series_name="Volumn",
                y_axis=volume_list,
                xaxis_index=1,
                yaxis_index=1,
                label_opts=opts.LabelOpts(is_show=False),
                # 根据 echarts demo 的原版是这么写的
                # itemstyle_opts=opts.ItemStyleOpts(
                #     color=JsCode("""
                #     function(params) {
                #         var colorList;
                #         if (data.datas[params.dataIndex][1]>data.datas[params.dataIndex][0]) {
                #           colorList = '#ef232a';
                #         } else {
                #           colorList = '#14b143';
                #         }
                #         return colorList;
                #     }
                #     """)
                # )
                # 改进后在 grid 中 add_js_funcs 后变成如下
                itemstyle_opts=opts.ItemStyleOpts(
                    color=JsCode(
                        """
                    function(params) {
                        var colorList;
                        if (barData[params.dataIndex][1] > barData[params.dataIndex][0]) {
                            colorList = '#ef232a';
                        } else {
                            colorList = '#14b143';
                        }
                        return colorList;
                    }
                    """
                    )
                ),
            )
                .set_global_opts(
                xaxis_opts=opts.AxisOpts(
                    type_="category",
                    grid_index=1,
                    axislabel_opts=opts.LabelOpts(is_show=False),
                ),
                legend_opts=opts.LegendOpts(is_show=False),
            )
        )

        return bar_1

class KChart_Main(KChart):
    """
    k线图的主图
    """

    def make_chart(self, k_model, is_line: bool, title:str, x_list: List[str],**param):
        CHART_TOTAL_SIZE = param['chart_size']
        k_bar_values = [k_item.k_value for k_item in k_model.k_items]
        k_bars = [k_item.bar for k_item in k_model.k_items]
        k_bar_size = len(k_model.k_items)

        MAX_SHOW_BAR_SIZE = 100 if k_model.is_daily else 250
        min_ = "dataMin"
        max_ = "dataMax"
        if k_bar_size > MAX_SHOW_BAR_SIZE:
            _range_start = int(100 * (1 - MAX_SHOW_BAR_SIZE / k_bar_size))
        else:
            _range_start = 0


        def make_turn_point_MarkPointItem(index:int,is_high:bool,is_line:bool)->opts.MarkPointItem:

            k_bar_value = k_bar_values[index]
            if is_line:
                coord_y = k_bar_value[1]
            else:
                coord_y = k_bar_value[3] if is_high else k_bar_value[2]
            if is_high:
                symbol_size = [20,20]
                _point_color = '#ef232a'
                _point_symbol = None
                coord_y = coord_y * 1.01
            else:
                symbol_size = [15,15]
                _point_color = '#14b143'
                _point_symbol = 'triangle'
                coord_y = coord_y * 0.95

            return opts.MarkPointItem(
                coord=[x_list[index], coord_y],  # 这里是直角坐标系x轴第三个，y轴第三个
                symbol=_point_symbol,  # 一般默认就好
                symbol_size=symbol_size,  # 一般默认就好
                itemstyle_opts=opts.ItemStyleOpts(color=_point_color),
            )

         ### 计算turnPoint
        # mark_point_data = []
        # if not is_line:
        #     bar_box = BarBox(full_size=k_bar_size)
        #     bar_box.extend(k_bars)
        #     turn_points = bar_box.get_turn_point(range_period=4)
        #     assert len(turn_points) == k_bar_size
        #     for i in range(0,k_bar_size):
        #         if turn_points[i] != 0:
        #             is_high = turn_points[i] > 0
        #             mark_point_data.append(make_turn_point_MarkPointItem(i,is_high,is_line))

        if is_line:
            k_bar_size = len(k_model.k_items)
            MAX_SHOW_BAR_SIZE = 100 if k_model.is_daily else 250
            if k_bar_size > MAX_SHOW_BAR_SIZE:
                _range_start = int(100 * (1 - MAX_SHOW_BAR_SIZE / k_bar_size))
            else:
                _range_start = 0
            close_values_list = [round(k_value[1] * 100) / 100 for k_value in k_bar_values]
            kline = (
                charts.Line()
                    .add_xaxis(xaxis_data=x_list)
                    .add_yaxis(
                    series_name="kline",
                    y_axis=close_values_list,
                    label_opts=opts.LabelOpts(is_show=False),
                    #markpoint_opts=opts.MarkPointOpts(data=mark_point_data),
                    ##itemstyle_opts=opts.ItemStyleOpts(color="#ec0000", color0="#00da3c"),
                )
                    .set_global_opts(
                    legend_opts=opts.LegendOpts(
                        is_show=False, pos_bottom=10, pos_left="center"
                    ),
                    title_opts=opts.TitleOpts(title=title, pos_top="90%"),
                    yaxis_opts=opts.AxisOpts(
                        is_scale=True,
                        splitarea_opts=opts.SplitAreaOpts(
                            is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
                        ),
                        min_=min_,
                        max_=max_,
                    ),
                    # xaxis_opts = opts.AxisOpts(
                    #     offset = 20,
                    # ),
                    datazoom_opts=[
                        opts.DataZoomOpts(
                            is_show=False,
                            type_="inside",
                            xaxis_index=[0, 1],
                            range_start=_range_start,
                            range_end=100,
                        ),
                        opts.DataZoomOpts(
                            is_show=True,
                            xaxis_index=[0, 1],
                            type_="slider",
                            pos_top="90%",
                            range_start=_range_start,
                            range_end=100,
                        ),
                        opts.DataZoomOpts(is_show=False, xaxis_index=[0, CHART_TOTAL_SIZE -1 ], range_start=_range_start, range_end=100),

                    ],
                    tooltip_opts=opts.TooltipOpts(
                        trigger="axis",
                        axis_pointer_type="cross",
                        background_color="rgba(245, 245, 245, 0.8)",
                        border_width=1,
                        border_color="#ccc",
                        textstyle_opts=opts.TextStyleOpts(color="#000"),
                    ),

                )
            )
            return kline
        else:
            tool_tip_fun = JsCode("""
                                                function(params) {
                                                  try{
                                                      var prices = params[0].data;
                                                      var open = prices[1];
                                                      var close = prices[2];
                                                      var low = prices[3];
                                                      var high = prices[4];
                                                      var pre_close = prices[5];
                                                      var pnl =  100 * (close - pre_close) / pre_close;
                                                      return  'pnl:  '+pnl.toFixed(2)+'%<br/>'+
                                                              'close:  ' + close.toFixed(2) + '<br/>'+
                                                              'open:   ' + open.toFixed(2) + '<br/>'+
                                                              'low     ' + low.toFixed(2) + '<br/>'+
                                                              'high:   ' + high.toFixed(2);
                                                  }catch(error){
                                                    return ''
                                                 }

                                              }
                                          """)
            kline = (
                charts.Kline()
                    .add_xaxis(xaxis_data=x_list)
                    .add_yaxis(
                    series_name="k柱",
                    y_axis=k_bar_values,
                    #markpoint_opts=opts.MarkPointOpts(data=mark_point_data),
                    itemstyle_opts=opts.ItemStyleOpts(color="#ec0000", color0="#00da3c"),
                )
                    .set_global_opts(
                    title_opts=opts.TitleOpts(title=title, pos_top="100%"),
                    legend_opts=opts.LegendOpts(
                        is_show=False, pos_bottom=10, pos_left="center"
                    ),
                    datazoom_opts=[
                        opts.DataZoomOpts(
                            is_show=False,
                            type_="inside",
                            xaxis_index=[0, 1],
                            range_start=_range_start,
                            range_end=100,
                        ),
                        opts.DataZoomOpts(
                            is_show=True,
                            xaxis_index=[0, 1],
                            type_="slider",
                            pos_top="90%",
                            range_start=_range_start,
                            range_end=100,
                        ),
                        opts.DataZoomOpts(is_show=False, xaxis_index=[0, CHART_TOTAL_SIZE - 1],range_start=_range_start, range_end=100),
                    ],
                    yaxis_opts=opts.AxisOpts(
                        is_scale=True,
                        splitarea_opts=opts.SplitAreaOpts(
                            is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
                        ),
                    ),
                    tooltip_opts=opts.TooltipOpts(
                        trigger="axis",
                        axis_pointer_type="cross",
                        background_color="rgba(245, 245, 245, 0.8)",
                        border_width=1,
                        border_color="#ccc",
                        formatter=tool_tip_fun,
                        textstyle_opts=opts.TextStyleOpts(color="#000"),
                    ),
                    xaxis_opts=opts.AxisOpts(
                        type_="category",
                        is_scale=True,
                        boundary_gap=False,
                        axisline_opts=opts.AxisLineOpts(is_on_zero=False),
                        splitline_opts=opts.SplitLineOpts(is_show=False),
                        split_number=20,
                        min_="dataMin",
                        max_="dataMax",
                    ),
                    # axispointer_opts=opts.AxisPointerOpts(
                    #     is_show=True,
                    #     link=[{"xAxisIndex": "all"}],
                    #     label=opts.LabelOpts(background_color="#777"),
                    # ),
                    brush_opts=opts.BrushOpts(
                        x_axis_index="all",
                        brush_link="all",
                        out_of_brush={"colorAlpha": 0.1},
                        brush_type="lineX",
                    ),
                )

            )

            if k_model.highlight_area is not  None:
                _name = k_model.highlight_area[2]
                _start = k_model.market_x_value(k_model.highlight_area[0])
                _end = k_model.market_x_value(k_model.highlight_area[1])

                kline.set_series_opts(
                    markarea_opts=opts.MarkAreaOpts(  # 标记区域配置项
                        data=[
                            opts.MarkAreaItem(name="持有", x=(_start, _end)),
                        ],
                    )
                )

            ma_lines = [5,10,30]
            if ma_lines:
                def calculate_ma(day_count: int, values: []):
                    result: List[Union[float, str]] = []
                    for i in range(len(values)):
                        if i < day_count:
                            result.append("-")
                            continue
                        sum_total = 0.0
                        for j in range(day_count):
                            sum_total += float(values[i - j][1])
                        result.append(abs(float("%.3f" % (sum_total / day_count))))
                    return result
                ma_chart_line = charts.Line()
                for ma in ma_lines:
                    ma_chart_line.add_xaxis(xaxis_data=x_list)
                    ma_chart_line.add_yaxis(
                        series_name=f"MA{ma}",
                        y_axis=calculate_ma(day_count=ma, values=k_bar_values),
                        is_smooth=True,
                        is_hover_animation=False,
                        linestyle_opts=opts.LineStyleOpts(width=0.5, opacity=0.5),
                        label_opts=opts.LabelOpts(is_show=False),
                        # tooltip_opts=opts.TooltipOpts(is_show=False)
                    )
                ma_chart_line.set_global_opts(xaxis_opts=opts.AxisOpts(type_="category"))
                kline = kline.overlap(ma_chart_line)

            return kline


class AROON_UP(KChart):

    def __init__(self):
        pass

    def make_chart(self, k_model, is_line: bool, title:str, x_list: List[str],**param):
        bar_box = BarBox(full_size=31)
        aroon_up_10_list = []
        aroon_up_20_list = []
        aroon_up_30_list = []
        aroon_up = []
        arron_diff = []
        for k_item  in k_model.k_items:
            bar_box.add(k_item.bar)
            down,aroon_up_10 = bar_box.arron(period=10,array=False)
            down,aroon_up_20 = bar_box.arron(period=20,array=False)
            down,aroon_up_30 = bar_box.arron(period=30,array=False)
            aroon_up_10_list.append(aroon_up_10)
            aroon_up_20_list.append(aroon_up_20)
            aroon_up_30_list.append(aroon_up_30)
            arron_diff.append((abs(aroon_up_30- aroon_up_20) + abs(aroon_up_10-aroon_up_20) + abs(aroon_up_30 -aroon_up_10)) / 2)
            aroon_up.append((aroon_up_10 + aroon_up_20 + aroon_up_30) / 3)

        chart_line = charts.Line()
        chart_line.add_xaxis(xaxis_data=x_list)
        chart_line.add_yaxis(
                series_name=f"arron_up",
                y_axis=aroon_up,
                is_smooth=True,
                is_hover_animation=False,
                linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
                label_opts=opts.LabelOpts(is_show=False),
                # tooltip_opts=opts.TooltipOpts(is_show=False)
            )
        chart_line.add_yaxis(
            series_name=f"arron_diff",
            y_axis=aroon_up_20_list,
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
            label_opts=opts.LabelOpts(is_show=False),
            # tooltip_opts=opts.TooltipOpts(is_show=False)
        )
        # chart_line.add_yaxis(
        #     series_name=f"arron_up_30",
        #     y_axis=aroon_up_30_list,
        #     is_smooth=True,
        #     is_hover_animation=False,
        #     linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
        #     label_opts=opts.LabelOpts(is_show=False),
        #     # tooltip_opts=opts.TooltipOpts(is_show=False)
        # )
        chart_line.set_global_opts(xaxis_opts=opts.AxisOpts(type_="category"))

        return chart_line


class ADOSC(KChart):

    def __init__(self):
        pass

    def make_chart(self, k_model, is_line: bool, title:str, x_list: List[str],**param):
        bar_box = BarBox(full_size=31)
        adosc_list = []
        for k_item  in k_model.k_items:
            bar_box.add(k_item.bar)
            adosc = bar_box.adsoc(fastperiod=3,slowperiod=10,array=False)
            adosc_list.append(adosc)

        chart_line = charts.Line()
        chart_line.add_xaxis(xaxis_data=x_list)
        chart_line.add_yaxis(
                series_name=f"adosc",
                y_axis=adosc_list,
                is_smooth=True,
                is_hover_animation=False,
                linestyle_opts=opts.LineStyleOpts(width=2, opacity=1),
                label_opts=opts.LabelOpts(is_show=False),
                # tooltip_opts=opts.TooltipOpts(is_show=False)
            )
        chart_line.set_global_opts(xaxis_opts=opts.AxisOpts(type_="category"))

        return chart_line